/*
Digital Image Processing - Final Project
9 December 2011

Joseph Dombrowski
Josh Dixon
Junmo An
*/

#include <string>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <iostream>
#include <stdio.h>
#include <iomanip>
#include "common.h"
#include "line.h"

#define R 2
#define G 1
#define B 0

#define _IMAGE 0
#define _HISTOGRAM 1
#define _EDGES 2

#define _GAUSSIAN 10
#define _AVERAGE 11

using namespace std;

class Image
{
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Object functions
	public:

	// Constructors
	Image();
	Image(string filename);
	Image(string filename, string imagename);
	Image(IplImage* inputImage, string imagename, double k, pointD center, double s);
	Image(vector<vector<edgePoint>> edgeMatrix, string imagename);
	Image(Image &source, string imagename);

	// Destructors
	~Image();
	void releaseImage();

	// Display
	void showImage();
	void hideImage();
	void showHistogram();
	void showHistogram(Image& theImage);
	void hideHistogram();
	void showEdges();
	void hideEdges();
	
	// Access Data
	unsigned char getImgPoint(point p, int c);
	unsigned char getImgPoint(point p);
	unsigned char getImgPoint(pointD p);
	double getK();
	double getS();
	pointD getCenter();

	unsigned char average();

	int width();
	int height();
	int channels();
	int depth();
	string name();

	IplImage* copyImg();

	void saveImage(string fName);

	// Simple manipulation
	void setImgPoint(point p, int channel, unsigned char v);
	void setImgPoint(point p, unsigned char v);
	void setImgPoint(point p, CvScalar color);
	void setImgPoint(point p, unsigned char red, unsigned char green, unsigned char blue);

	void setWhite();
	void setColor(CvScalar color);
	void setColor(unsigned char intensity);
	void setColor(unsigned char red, unsigned char green, unsigned char blue);

	void drawLabel(string message, point thePoint, CvScalar color, int _width, double _size);

	// Image processing
	int histogram(vector<int>& histogram);
	int histogram();
	
	void thresholdImg(int thresh);
	void thresholdImg(IplImage* result, int thresh);

	void drawImgAt(IplImage* source, point p);
	IplImage* zeroPad(int top, int right, int bottom, int left);

	void smoothImg(int type);
	void smoothImg(int type, int size);

	void detectEdges(vector<edge>& edges);
	double calculateDistortion(pointD centerOfDistortion, double kFactor, double s);
	double calculateDistortion();
	void minimizeDistortionByAdjustingK();
	void minimizeDistortionByAdjustingCenterOfDistortion();
	void minimizeDistortionByAdjustingS();
	void correctDistortion();

	private:
	// Member variables
	IplImage* image;
	string windowName;
	vector<vector<edgePoint>> edgeMap;
	vector<int> imgHist;
	vector<edge> imgEdges;
	bool initialized[3];
	double k_distortionFactor;
	double s_aspectRatio;
	pointD centerOfDistortion;
	int longEdge;

	// Initialization functions
	void initializeImage();
	void clearMaps();

	void mapEdges(vector<vector<edgePoint>>& edgeMatrix);
	void suppressEdges(vector<vector<edgePoint>>& edgeMatrix);
	void threshold(vector<vector<edgePoint>>& edgeMatrix, int threshLow, int threshHigh);
	void mergeEdges(vector<edge>& edges);
	void pushPoint(int edgeNum, point thePoint, vector<edge>& edges);
	double getThresh(vector<vector<edgePoint>>& edgeMatrix);

	double findRad(double diag, double K, double Ru);

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// Static functions
	public:

	// Display
	static void showImage(IplImage* theImage, string imagename);

	// Access data
	static unsigned char getImgPoint(IplImage* source, point p, int channel);
	static unsigned char getImgPoint(IplImage* source, point p);
	
	// Simple manipulation
	static void setImgPoint(IplImage* result, point p, int channel, unsigned char v);
	static void setImgPoint(IplImage* result, point p, unsigned char v);
	static void setImgPoint(IplImage* result, point p, CvScalar color);
	static void setImgPoint(IplImage* result, point p, unsigned char red, unsigned char green, unsigned char blue);
	
	static void setWhite(IplImage* result);
	static void setColor(IplImage* result, CvScalar color);
	static void setColor(IplImage* result, unsigned char intensity);
	static void setColor(IplImage* result, unsigned char red, unsigned char green, unsigned char blue);

	// Process image
	static IplImage* copyImg(IplImage* source);
	static IplImage* zeroPad(IplImage* source, int top, int right, int bottom, int left);
};